﻿using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Text;

namespace eStock.Common
{
    //internal class CryptLib
    //{
    //    private const string WopDefaultPwd = "";
    //    private readonly byte[] _mBytOnBits = new byte[8];
    //    private readonly long[] _mL2Power = new long[31];
    //    private readonly long[] _mLOnBits = new long[31];
    //    private readonly byte[] _mInCo = new byte[4];
    //    private readonly byte[] m_byt2Power = new byte[8];
    //    private readonly byte[] m_fbsub = new byte[256];
    //    private readonly byte[] m_fi = new byte[24];
    //    private readonly long[] m_fkey = new long[120];
    //    private readonly long[] m_ftable = new long[256];
    //    private readonly byte[] m_ltab = new byte[256];
    //    private readonly byte[] m_ptab = new byte[256];
    //    private readonly byte[] m_rbsub = new byte[256];
    //    private readonly long[] m_rco = new long[30];
    //    private readonly byte[] m_ri = new byte[24];

    //    private readonly long[] m_rkey = new long[120];
    //    private readonly long[] m_rtable = new long[256];
    //    private int m_Nb;
    //    private int m_Nk;
    //    private int m_Nr;

    //    public CryptLib()
    //    {
    //        Debug.Print("Initializing AES");
    //        _mInCo[0] = 0xb;
    //        // 11
    //        _mInCo[1] = 0xd;
    //        // 13
    //        _mInCo[2] = 0x9;
    //        // 9
    //        _mInCo[3] = 0xe;
    //        // 14

    //        _mBytOnBits[0] = 1;
    //        // 00000001
    //        _mBytOnBits[1] = 3;
    //        // 00000011
    //        _mBytOnBits[2] = 7;
    //        // 00000111
    //        _mBytOnBits[3] = 15;
    //        // 00001111
    //        _mBytOnBits[4] = 31;
    //        // 00011111
    //        _mBytOnBits[5] = 63;
    //        // 00111111
    //        _mBytOnBits[6] = 127;
    //        // 01111111
    //        _mBytOnBits[7] = 255;
    //        // 11111111

    //        m_byt2Power[0] = 1;
    //        // 00000001
    //        m_byt2Power[1] = 2;
    //        // 00000010
    //        m_byt2Power[2] = 4;
    //        // 00000100
    //        m_byt2Power[3] = 8;
    //        // 00001000
    //        m_byt2Power[4] = 16;
    //        // 00010000
    //        m_byt2Power[5] = 32;
    //        // 00100000
    //        m_byt2Power[6] = 64;
    //        // 01000000
    //        m_byt2Power[7] = 128;
    //        // 10000000

    //        _mLOnBits[0] = 1;
    //        // 00000000000000000000000000000001
    //        _mLOnBits[1] = 3;
    //        // 00000000000000000000000000000011
    //        _mLOnBits[2] = 7;
    //        // 00000000000000000000000000000111
    //        _mLOnBits[3] = 15;
    //        // 00000000000000000000000000001111
    //        _mLOnBits[4] = 31;
    //        // 00000000000000000000000000011111
    //        _mLOnBits[5] = 63;
    //        // 00000000000000000000000000111111
    //        _mLOnBits[6] = 127;
    //        // 00000000000000000000000001111111
    //        _mLOnBits[7] = 255;
    //        // 00000000000000000000000011111111
    //        _mLOnBits[8] = 511;
    //        // 00000000000000000000000111111111
    //        _mLOnBits[9] = 1023;
    //        // 00000000000000000000001111111111
    //        _mLOnBits[10] = 2047;
    //        // 00000000000000000000011111111111
    //        _mLOnBits[11] = 4095;
    //        // 00000000000000000000111111111111
    //        _mLOnBits[12] = 8191;
    //        // 00000000000000000001111111111111
    //        _mLOnBits[13] = 16383;
    //        // 00000000000000000011111111111111
    //        _mLOnBits[14] = 32767;
    //        // 00000000000000000111111111111111
    //        _mLOnBits[15] = 65535;
    //        // 00000000000000001111111111111111
    //        _mLOnBits[16] = 131071;
    //        // 00000000000000011111111111111111
    //        _mLOnBits[17] = 262143;
    //        // 00000000000000111111111111111111
    //        _mLOnBits[18] = 524287;
    //        // 00000000000001111111111111111111
    //        _mLOnBits[19] = 1048575;
    //        // 00000000000011111111111111111111
    //        _mLOnBits[20] = 2097151;
    //        // 00000000000111111111111111111111
    //        _mLOnBits[21] = 4194303;
    //        // 00000000001111111111111111111111
    //        _mLOnBits[22] = 8388607;
    //        // 00000000011111111111111111111111
    //        _mLOnBits[23] = 16777215;
    //        // 00000000111111111111111111111111
    //        _mLOnBits[24] = 33554431;
    //        // 00000001111111111111111111111111
    //        _mLOnBits[25] = 67108863;
    //        // 00000011111111111111111111111111
    //        _mLOnBits[26] = 134217727;
    //        // 00000111111111111111111111111111
    //        _mLOnBits[27] = 268435455;
    //        // 00001111111111111111111111111111
    //        _mLOnBits[28] = 536870911;
    //        // 00011111111111111111111111111111
    //        _mLOnBits[29] = 1073741823;
    //        // 00111111111111111111111111111111
    //        _mLOnBits[30] = 2147483647;
    //        // 01111111111111111111111111111111

    //        _mL2Power[0] = 1;
    //        // 00000000000000000000000000000001
    //        _mL2Power[1] = 2;
    //        // 00000000000000000000000000000010
    //        _mL2Power[2] = 4;
    //        // 00000000000000000000000000000100
    //        _mL2Power[3] = 8;
    //        // 00000000000000000000000000001000
    //        _mL2Power[4] = 16;
    //        // 00000000000000000000000000010000
    //        _mL2Power[5] = 32;
    //        // 00000000000000000000000000100000
    //        _mL2Power[6] = 64;
    //        // 00000000000000000000000001000000
    //        _mL2Power[7] = 128;
    //        // 00000000000000000000000010000000
    //        _mL2Power[8] = 256;
    //        // 00000000000000000000000100000000
    //        _mL2Power[9] = 512;
    //        // 00000000000000000000001000000000
    //        _mL2Power[10] = 1024;
    //        // 00000000000000000000010000000000
    //        _mL2Power[11] = 2048;
    //        // 00000000000000000000100000000000
    //        _mL2Power[12] = 4096;
    //        // 00000000000000000001000000000000
    //        _mL2Power[13] = 8192;
    //        // 00000000000000000010000000000000
    //        _mL2Power[14] = 16384;
    //        // 00000000000000000100000000000000
    //        _mL2Power[15] = 32768;
    //        // 00000000000000001000000000000000
    //        _mL2Power[16] = 65536;
    //        // 00000000000000010000000000000000
    //        _mL2Power[17] = 131072;
    //        // 00000000000000100000000000000000
    //        _mL2Power[18] = 262144;
    //        // 00000000000001000000000000000000
    //        _mL2Power[19] = 524288;
    //        // 00000000000010000000000000000000
    //        _mL2Power[20] = 1048576;
    //        // 00000000000100000000000000000000
    //        _mL2Power[21] = 2097152;
    //        // 00000000001000000000000000000000
    //        _mL2Power[22] = 4194304;
    //        // 00000000010000000000000000000000
    //        _mL2Power[23] = 8388608;
    //        // 00000000100000000000000000000000
    //        _mL2Power[24] = 16777216;
    //        // 00000001000000000000000000000000
    //        _mL2Power[25] = 33554432;
    //        // 00000010000000000000000000000000
    //        _mL2Power[26] = 67108864;
    //        // 00000100000000000000000000000000
    //        _mL2Power[27] = 134217728;
    //        // 00001000000000000000000000000000
    //        _mL2Power[28] = 268435456;
    //        // 00010000000000000000000000000000
    //        _mL2Power[29] = 536870912;
    //        // 00100000000000000000000000000000
    //        _mL2Power[30] = 1073741824;
    //        // 01000000000000000000000000000000
    //    }

    //    private long LShift(long lValue, int iShiftBits)
    //    {
    //        long functionReturnValue;

    //        if (iShiftBits == 0)
    //        {
    //            functionReturnValue = lValue;
    //            return functionReturnValue;
    //        }
    //        if (iShiftBits == 31)
    //        {
    //            functionReturnValue = Convert.ToBoolean(lValue & 1) ? 0x80000000 : 0;
    //            return functionReturnValue;
    //        }
    //        if (iShiftBits < 0 | iShiftBits > 31)
    //        {
    //            throw new Exception("Error 6");
    //        }

    //        if (Convert.ToBoolean((lValue & _mL2Power[31 - iShiftBits])))
    //        {
    //            functionReturnValue = ((lValue & _mLOnBits[31 - (iShiftBits + 1)])*_mL2Power[iShiftBits]) | 0x80000000;
    //        }
    //        else
    //        {
    //            functionReturnValue = ((lValue & _mLOnBits[31 - iShiftBits])*_mL2Power[iShiftBits]);
    //        }
    //        return functionReturnValue;
    //    }

    //    private long RShift(long lValue, int iShiftBits)
    //    {
    //        long functionReturnValue;

    //        if (iShiftBits == 0)
    //        {
    //            functionReturnValue = lValue;
    //            return functionReturnValue;
    //        }
    //        if (iShiftBits == 31)
    //        {
    //            functionReturnValue = Convert.ToBoolean(lValue & 0x80000000) ? 1 : 0;
    //            return functionReturnValue;
    //        }
    //        if (iShiftBits < 0 | iShiftBits > 31)
    //        {
    //            throw new Exception("Error 6");
    //        }

    //        functionReturnValue = (lValue & 0x7ffffffe)/_mL2Power[iShiftBits];

    //        if (Convert.ToBoolean((lValue & 0x80000000)))
    //        {
    //            functionReturnValue = (functionReturnValue | (0x40000000/_mL2Power[iShiftBits - 1]));
    //        }
    //        return functionReturnValue;
    //    }

    //    private byte LShiftByte(byte bytValue, byte bytShiftBits)
    //    {
    //        byte functionReturnValue;

    //        if (bytShiftBits == 0)
    //        {
    //            functionReturnValue = bytValue;
    //            return functionReturnValue;
    //        }
    //        if (bytShiftBits == 7)
    //        {
    //            if (Convert.ToBoolean(bytValue & 1))
    //            {
    //                functionReturnValue = 0x80;
    //            }
    //            else
    //            {
    //                functionReturnValue = 0;
    //            }
    //            return functionReturnValue;
    //        }
    //        if (bytShiftBits < 0 | bytShiftBits > 7)
    //        {
    //            throw new Exception("Error 6");
    //        }

    //        functionReturnValue = (byte) ((bytValue & _mBytOnBits[7 - bytShiftBits])*m_byt2Power[bytShiftBits]);
    //        return functionReturnValue;
    //    }

    //    private byte RShiftByte(byte bytValue, byte bytShiftBits)
    //    {
    //        byte functionReturnValue = 0;

    //        if (bytShiftBits == 0)
    //        {
    //            functionReturnValue = bytValue;
    //            return functionReturnValue;
    //        }
    //        if (bytShiftBits == 7)
    //        {
    //            if (Convert.ToBoolean(bytValue & 0x80))
    //            {
    //                functionReturnValue = 1;
    //            }
    //            else
    //            {
    //                functionReturnValue = 0;
    //            }
    //            return functionReturnValue;
    //        }
    //        if (bytShiftBits < 0 | bytShiftBits > 7)
    //        {
    //            throw new Exception("Error 6");
    //        }

    //        functionReturnValue = (byte) (bytValue/m_byt2Power[bytShiftBits]);
    //        return functionReturnValue;
    //    }

    //    private long RotateLeft(long lValue, int iShiftBits)
    //    {
    //        return LShift(lValue, iShiftBits) | RShift(lValue, (32 - iShiftBits));
    //    }

    //    private byte RotateLeftByte(byte bytValue, byte bytShiftBits)
    //    {
    //        return
    //            (byte) (LShiftByte(bytValue, bytShiftBits) | RShiftByte(bytValue, Convert.ToByte((8 - bytShiftBits))));
    //    }

    //    private long Pack(byte[] b)
    //    {
    //        long functionReturnValue = 0;

    //        long lCount = 0;
    //        long lTemp = 0;

    //        for (lCount = 0; lCount <= 3; lCount++)
    //        {
    //            lTemp = b[Convert.ToInt32(lCount)];
    //            functionReturnValue = functionReturnValue | LShift(lTemp, Convert.ToInt32((lCount*8)));
    //        }
    //        return functionReturnValue;
    //    }

    //    private long PackFrom(byte[] b, long k)
    //    {
    //        long functionReturnValue = 0;

    //        long lCount;

    //        for (lCount = 0; lCount <= 3; lCount++)
    //        {
    //            long lTemp = b[Convert.ToInt32(lCount + k)];
    //            functionReturnValue = functionReturnValue | LShift(lTemp, Convert.ToInt32((lCount*8)));
    //        }
    //        return functionReturnValue;
    //    }


    //    private void Unpack(long a, byte[] b)
    //    {
    //        b[0] = Convert.ToByte(a & _mLOnBits[7]);
    //        b[1] = Convert.ToByte(RShift(a, 8) & _mLOnBits[7]);
    //        b[2] = Convert.ToByte(RShift(a, 16) & _mLOnBits[7]);
    //        b[3] = Convert.ToByte(RShift(a, 24) & _mLOnBits[7]);
    //    }

    //    private void UnpackFrom(long a, byte[] b, long k)
    //    {
    //        b[Convert.ToInt32(0 + k)] = Convert.ToByte(a & _mLOnBits[7]);
    //        b[Convert.ToInt32(1 + k)] = Convert.ToByte(RShift(a, 8) & _mLOnBits[7]);
    //        b[Convert.ToInt32(2 + k)] = Convert.ToByte(RShift(a, 16) & _mLOnBits[7]);
    //        b[Convert.ToInt32(3 + k)] = Convert.ToByte(RShift(a, 24) & _mLOnBits[7]);
    //    }

    //    private byte Xtime(byte a)
    //    {
    //        byte b = 0;

    //        if (Convert.ToBoolean((a & 0x80)))
    //        {
    //            b = 0x1b;
    //        }
    //        else
    //        {
    //            b = 0;
    //        }

    //        a = LShiftByte(a, 1);
    //        a = (byte) (a ^ b);

    //        return a;
    //    }

    //    private byte Bmul(byte x, byte y)
    //    {
    //        byte functionReturnValue;

    //        if (x != 0 & y != 0)
    //        {
    //            functionReturnValue =
    //                m_ptab[Convert.ToInt32((Convert.ToInt64(m_ltab[x]) + Convert.ToInt64(m_ltab[y]))%255)];
    //        }
    //        else
    //        {
    //            functionReturnValue = 0;
    //        }
    //        return functionReturnValue;
    //    }

    //    private long SubByte(long a)
    //    {
    //        var b = new byte[4];

    //        Unpack(a, b);
    //        b[0] = m_fbsub[b[0]];
    //        b[1] = m_fbsub[b[1]];
    //        b[2] = m_fbsub[b[2]];
    //        b[3] = m_fbsub[b[3]];

    //        return Pack(b);
    //    }

    //    private long Product(long x, long y)
    //    {
    //        var xb = new byte[4];
    //        var yb = new byte[4];

    //        Unpack(x, xb);
    //        Unpack(y, yb);
    //        return Bmul(xb[0], yb[0]) ^ Bmul(xb[1], yb[1]) ^ Bmul(xb[2], yb[2]) ^ Bmul(xb[3], yb[3]);
    //    }

    //    private long InvMixCol(long x)
    //    {
    //        var b = new byte[4];

    //        long m = Pack(_mInCo);
    //        b[3] = Convert.ToByte(Product(m, x));
    //        m = RotateLeft(m, 24);
    //        b[2] = Convert.ToByte(Product(m, x));
    //        m = RotateLeft(m, 24);
    //        b[1] = Convert.ToByte(Product(m, x));
    //        m = RotateLeft(m, 24);
    //        b[0] = Convert.ToByte(Product(m, x));
    //        long y = Pack(b);

    //        return y;
    //    }

    //    private byte ByteSub(byte x)
    //    {
    //        byte y = 0;

    //        y = m_ptab[255 - m_ltab[x]];
    //        x = y;
    //        x = RotateLeftByte(x, 1);
    //        y = (byte) (y ^ x);
    //        x = RotateLeftByte(x, 1);
    //        y = (byte) (y ^ x);
    //        x = RotateLeftByte(x, 1);
    //        y = (byte) (y ^ x);
    //        x = RotateLeftByte(x, 1);
    //        y = (byte) (y ^ x);
    //        y = Convert.ToByte(y ^ 0x63);

    //        return y;
    //    }

    //    private void Gentables()
    //    {
    //        long i = 0;
    //        byte y = 0;
    //        var b = new byte[4];
    //        byte ib = 0;

    //        m_ltab[0] = 0;
    //        m_ptab[0] = 1;
    //        m_ltab[1] = 0;
    //        m_ptab[1] = 3;
    //        m_ltab[3] = 1;

    //        for (i = 2; i <= 255; i++)
    //        {
    //            m_ptab[Convert.ToInt32(i)] =
    //                (byte) (m_ptab[Convert.ToInt32(i - 1)] ^ Xtime(m_ptab[Convert.ToInt32(i - 1)]));
    //            m_ltab[m_ptab[Convert.ToInt32(i)]] = Convert.ToByte(i);
    //        }

    //        m_fbsub[0] = 0x63;
    //        m_rbsub[0x63] = 0;

    //        for (i = 1; i <= 255; i++)
    //        {
    //            ib = Convert.ToByte(i);
    //            y = ByteSub(ib);
    //            m_fbsub[Convert.ToInt32(i)] = y;
    //            m_rbsub[y] = Convert.ToByte(i);
    //        }

    //        y = 1;

    //        for (i = 0; i <= 29; i++)
    //        {
    //            m_rco[Convert.ToInt32(i)] = y;
    //            y = Xtime(y);
    //        }

    //        for (i = 0; i <= 255; i++)
    //        {
    //            y = m_fbsub[Convert.ToInt32(i)];
    //            b[3] = (byte) (y ^ Xtime(y));
    //            b[2] = y;
    //            b[1] = y;
    //            b[0] = Xtime(y);
    //            m_ftable[Convert.ToInt32(i)] = Pack(b);

    //            y = m_rbsub[Convert.ToInt32(i)];
    //            b[3] = Bmul(_mInCo[0], y);
    //            b[2] = Bmul(_mInCo[1], y);
    //            b[1] = Bmul(_mInCo[2], y);
    //            b[0] = Bmul(_mInCo[3], y);
    //            m_rtable[Convert.ToInt32(i)] = Pack(b);
    //        }
    //    }

    //    private void Gkey(int nb, int nk, byte[] key)
    //    {
    //        int i = 0;
    //        int j = 0;
    //        int k = 0;
    //        int m = 0;
    //        int N = 0;
    //        int C1 = 0;
    //        int C2 = 0;
    //        int C3 = 0;
    //        var CipherKey = new long[8];

    //        m_Nb = nb;
    //        m_Nk = nk;

    //        if (m_Nb >= m_Nk)
    //        {
    //            m_Nr = 6 + m_Nb;
    //        }
    //        else
    //        {
    //            m_Nr = 6 + m_Nk;
    //        }

    //        C1 = 1;

    //        if (m_Nb < 8)
    //        {
    //            C2 = 2;
    //            C3 = 3;
    //        }
    //        else
    //        {
    //            C2 = 3;
    //            C3 = 4;
    //        }

    //        for (j = 0; j < nb; j++)
    //        {
    //            m = j*3;

    //            m_fi[m] = Convert.ToByte((j + C1)%nb);
    //            m_fi[m + 1] = Convert.ToByte((j + C2)%nb);
    //            m_fi[m + 2] = Convert.ToByte((j + C3)%nb);
    //            m_ri[m] = Convert.ToByte((nb + j - C1)%nb);
    //            m_ri[m + 1] = Convert.ToByte((nb + j - C2)%nb);
    //            m_ri[m + 2] = Convert.ToByte((nb + j - C3)%nb);
    //        }

    //        N = m_Nb*(m_Nr + 1);

    //        for (i = 0; i < m_Nk; i++)
    //        {
    //            j = i*4;
    //            CipherKey[i] = PackFrom(key, j);
    //        }

    //        for (i = 0; i < m_Nk; i++)
    //        {
    //            m_fkey[i] = CipherKey[i];
    //        }

    //        j = m_Nk;
    //        k = 0;

    //        while (j < N)
    //        {
    //            m_fkey[j] = m_fkey[j - m_Nk] ^
    //                                         SubByte(RotateLeft(m_fkey[j - 1], 24)) ^
    //                                         m_rco[k];

    //            if (m_Nk <= 6)
    //            {
    //                i = 1;

    //                while (i < m_Nk & (i + j) < N)
    //                {
    //                    m_fkey[i + j] = m_fkey[i + j - m_Nk] ^
    //                                                     m_fkey[i + j - 1];
    //                    i++;
    //                }
    //            }
    //            else
    //            {
    //                i = 1;

    //                while (i < 4 & (i + j) < N)
    //                {
    //                    m_fkey[i + j] = m_fkey[i + j - m_Nk] ^
    //                                                     m_fkey[i + j - 1];
    //                    i++;
    //                }

    //                if (j + 4 < N)
    //                {
    //                    m_fkey[j + 4] = m_fkey[j + 4 - m_Nk] ^
    //                                                     SubByte(m_fkey[j + 3]);
    //                }

    //                i = 5;

    //                while (i < m_Nk & (i + j) < N)
    //                {
    //                    m_fkey[i + j] = m_fkey[i + j - m_Nk] ^
    //                                                     m_fkey[i + j - 1];
    //                    i = i + 1;
    //                }
    //            }

    //            j = j + m_Nk;
    //            k = k + 1;
    //        }

    //        for (j = 0; j < m_Nb; j++)
    //        {
    //            m_rkey[j + N - nb] = m_fkey[j];
    //        }

    //        i = m_Nb;

    //        while (i < N - m_Nb)
    //        {
    //            k = N - m_Nb - i;

    //            for (j = 0; j < m_Nb; j++)
    //            {
    //                m_rkey[k + j] = InvMixCol(m_fkey[i + j]);
    //            }

    //            i = i + m_Nb;
    //        }

    //        j = N - m_Nb;

    //        while (j < N)
    //        {
    //            m_rkey[j - N + m_Nb] = m_fkey[j];
    //            j++;
    //        }
    //    }


    //    private void Encrypt(byte[] buff)
    //    {
    //        long i = 0;
    //        long j = 0;
    //        long k = 0;
    //        long m = 0;
    //        var a = new long[8];
    //        var b = new long[8];
    //        long[] x = null;
    //        long[] y = null;
    //        long[] t = null;

    //        for (i = 0; i <= m_Nb - 1; i++)
    //        {
    //            j = i*4;

    //            a[Convert.ToInt32(i)] = PackFrom(buff, j);
    //            a[Convert.ToInt32(i)] = a[Convert.ToInt32(i)] ^ m_fkey[Convert.ToInt32(i)];
    //        }

    //        k = m_Nb;
    //        x = a;
    //        y = b;


    //        for (i = 1; i <= m_Nr - 1; i++)
    //        {
    //            for (j = 0; j <= m_Nb - 1; j++)
    //            {
    //                m = j*3;
    //                y[Convert.ToInt32(j)] = m_fkey[Convert.ToInt32(k)] ^
    //                                        m_ftable[Convert.ToInt32(x[Convert.ToInt32(j)] & _mLOnBits[7])] ^
    //                                        RotateLeft(
    //                                            m_ftable[
    //                                                Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m)]], 8) &
    //                                                                _mLOnBits[7])], 8) ^
    //                                        RotateLeft(
    //                                            m_ftable[
    //                                                Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m + 1)]], 16) &
    //                                                                _mLOnBits[7])], 16) ^
    //                                        RotateLeft(
    //                                            m_ftable[
    //                                                Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m + 2)]], 24) &
    //                                                                _mLOnBits[7])], 24);
    //                k = k + 1;
    //            }

    //            t = x;
    //            x = y;
    //            y = t;
    //        }

    //        for (j = 0; j <= m_Nb - 1; j++)
    //        {
    //            m = j*3;
    //            y[Convert.ToInt32(j)] = m_fkey[Convert.ToInt32(k)] ^
    //                                    m_fbsub[Convert.ToInt32(x[Convert.ToInt32(j)] & _mLOnBits[7])] ^
    //                                    RotateLeft(
    //                                        m_fbsub[
    //                                            Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m)]], 8) & _mLOnBits[7])],
    //                                        8) ^
    //                                    RotateLeft(
    //                                        m_fbsub[
    //                                            Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m + 1)]], 16) &
    //                                                            _mLOnBits[7])], 16) ^
    //                                    RotateLeft(
    //                                        m_fbsub[
    //                                            Convert.ToInt32(RShift(x[m_fi[Convert.ToInt32(m + 2)]], 24) &
    //                                                            _mLOnBits[7])], 24);
    //            k = k + 1;
    //        }

    //        for (i = 0; i <= m_Nb - 1; i++)
    //        {
    //            j = i*4;
    //            UnpackFrom(y[Convert.ToInt32(i)], buff, j);
    //            x[Convert.ToInt32(i)] = 0;
    //            y[Convert.ToInt32(i)] = 0;
    //        }
    //    }


    //    private void Decrypt(byte[] buff)
    //    {
    //        int i;
    //        int j;
    //        int k;
    //        int m;
    //        var a = new long[8];
    //        var b = new long[8];
    //        long[] t;

    //        for (i = 0; i < m_Nb; i++)
    //        {
    //            j = i*4;
    //            a[i] = PackFrom(buff, j);
    //            a[i] = a[i] ^ m_rkey[i];
    //        }

    //        k = m_Nb;
    //        long[] x = a;
    //        long[] y = b;


    //        for (i = 1; i < m_Nr; i++)
    //        {
    //            for (j = 0; j < m_Nb; j++)
    //            {
    //                m = j*3;
    //                y[j] = m_rkey[k] ^ m_rtable[x[j] & _mLOnBits[7]] ^
    //                                        RotateLeft(m_rtable[RShift(x[m_ri[m]], 8) &_mLOnBits[7]], 8) ^
    //                                        RotateLeft(m_rtable[RShift(x[m_ri[m + 1]], 16) &_mLOnBits[7]], 16) ^
    //                                        RotateLeft(m_rtable[RShift(x[m_ri[m + 2]], 24) & _mLOnBits[7]], 24);
    //                k++;
    //            }

    //            t = x;
    //            x = y;
    //            y = t;
    //        }

    //        for (j = 0; j < m_Nb; j++)
    //        {
    //            m = j*3;

    //            y[j] = m_rkey[k] ^ m_rbsub[x[j] & _mLOnBits[7]] ^
    //                                    RotateLeft( m_rbsub[RShift(x[m_ri[m]], 8) & _mLOnBits[7]], 8) ^
    //                                    RotateLeft( m_rbsub[RShift(x[m_ri[m + 1]], 16) & _mLOnBits[7]], 16) ^
    //                                    RotateLeft( m_rbsub[RShift(x[m_ri[m + 2]], 24) & _mLOnBits[7]], 24);
    //            k = k + 1;
    //        }

    //        for (i = 0; i < m_Nb; i++)
    //        {
    //            j = i*4;

    //            UnpackFrom(y[i], buff, j);
    //            x[i] = 0;
    //            y[i] = 0;
    //        }
    //    }

    //    private bool IsInitialized(ref byte[] vArray)
    //    {
    //        // ERROR: Not supported in C#: OnErrorStatement

    //        return vArray.Length > 0;
    //    }

    //    private byte[] EncryptData(byte[] bytMessage, byte[] bytPassword)
    //    {
    //        var bytKey = new byte[32];
    //        byte[] bytIn;
    //        byte[] bytOut;
    //        var bytTemp = new byte[32];
    //        int lCount = 0;
    //        long lLength = 0;
    //        long lEncodedLength = 0;
    //        var bytLen = new byte[4];


    //        if (!IsInitialized(ref bytMessage))
    //        {
    //            return null;
    //        }

    //        if (!IsInitialized(ref bytPassword))
    //        {
    //            return null;
    //        }

    //        for (lCount = 0; lCount < bytPassword.Length; lCount++)
    //        {
    //            bytKey[Convert.ToInt32(lCount)] = bytPassword[Convert.ToInt32(lCount)];

    //            if (lCount == 31)
    //            {
    //                break; // TODO: might not be correct. Was : Exit For
    //            }
    //        }

    //        Gentables();
    //        Gkey(8, 8, bytKey);

    //        lLength = bytMessage.Length;
    //        lEncodedLength = lLength + 4;

    //        if (lEncodedLength%32 != 0)
    //        {
    //            lEncodedLength = lEncodedLength + 32 - (lEncodedLength%32);
    //        }

    //        bytIn = new byte[lEncodedLength];
    //        bytOut = new byte[lEncodedLength];

    //        bytIn[0] = Convert.ToByte(lLength);

    //        int i = 0;
    //        //Dim l As Integer

    //        for (i = 0; i < Convert.ToInt32(lLength); i++)
    //        {
    //            bytIn[4 + i] = bytMessage[i];
    //        }


    //        for (lCount = 0; lCount < lEncodedLength; lCount += 32)
    //        {
    //            int j = 0;
    //            int k = lCount;
    //            for (i = Convert.ToInt32(lCount); i < bytIn.Length; i++)
    //            {
    //                bytTemp[j] = bytIn[i];
    //                j++;
    //                if (j == 32)
    //                {
    //                    break; // TODO: might not be correct. Was : Exit For
    //                }
    //            }

    //            Encrypt(bytTemp);

    //            for (i = 0; i < bytTemp.Length; i++)
    //            {
    //                bytOut[k] = bytTemp[i];
    //                k++;
    //            }
    //        }

    //        byte[] functionReturnValue = bytOut;
    //        return functionReturnValue;
    //    }

    //    private byte[] DecryptData(byte[] bytIn, byte[] bytPassword)
    //    {
    //        byte[] functionReturnValue = null;

    //        int i;
    //        int j;
    //        int k;
    //        var bytKey = new byte[32];
    //        var bytTemp = new byte[32];
    //        int lCount;

    //        if (!IsInitialized(ref bytIn))
    //        {
    //            return null;
    //        }

    //        if (!IsInitialized(ref bytPassword))
    //        {
    //            return null;
    //        }

    //        int lEncodedLength = bytIn.Length;

    //        if (lEncodedLength%32 != 0)
    //        {
    //            return null;
    //        }

    //        for (lCount = 0; lCount < bytPassword.Length; lCount++)
    //        {
    //            bytKey[lCount] = bytPassword[lCount];

    //            if (lCount == 31)
    //            {
    //                break; // TODO: might not be correct. Was : Exit For
    //            }
    //        }

    //        Gentables();
    //        Gkey(8, 8, bytKey);

    //        byte[] bytOut = new byte[lEncodedLength];

    //        for (lCount = 0; lCount < lEncodedLength; lCount += 32)
    //        {
    //            j = 0;
    //            k = lCount;
    //            for (i = lCount; i < bytIn.Length; i++)
    //            {
    //                bytTemp[j] = bytIn[i];
    //                j++;
    //                if (j == 32)
    //                {
    //                    break; // TODO: might not be correct. Was : Exit For
    //                }
    //            }
    //            Decrypt(bytTemp);
    //            for (i = 0; i < bytTemp.Length; i++)
    //            {
    //                bytOut[k] = bytTemp[i];
    //                k++;
    //            }
    //        }

    //        long lLength = bytOut[0];

    //        if (lLength > lEncodedLength - 4)
    //        {
    //            return null;
    //        }

    //        byte[] bytMessage = new byte[lLength];
    //        for (i = 0; i < bytMessage.Length; i++)
    //        {
    //            bytMessage[i] = bytOut[4 + i];
    //        }

    //        functionReturnValue = bytMessage;
    //        return functionReturnValue;
    //    }

    //    private string ConvertEncryptedByteDataToEncryptedString(ref byte[] paramBytOut)
    //    {
    //        string sTemp = BitConverter.ToString(paramBytOut).Replace("-", string.Empty);
    //        return sTemp;
    //    }

    //    private byte[] ConvertEncryptedStringDataToEncryptedByteData(string paramStrData)
    //    {
    //        ASCIIEncoding enc = new ASCIIEncoding();
    //        return enc.GetBytes(paramStrData);
    //    }

    //    public string EncryptString(string unencryptedString, string zertifikat)
    //    {
    //        byte[] EncryptionKey = null;
    //        byte[] EncryptedPwd = null;
    //        byte[] SecretString = null;

    //        if ((zertifikat.Length == 0))
    //        {
    //            zertifikat = WopDefaultPwd;
    //        }

    //        if ((unencryptedString.Length == 0))
    //        {
    //            throw new Exception("Emtpy String");
    //        }
    //        if ((unencryptedString.Length > 16000))
    //        {
    //            throw new Exception("String to large");
    //        }

    //        EncryptionKey = Encoding.Default.GetBytes(zertifikat);

    //        int i = EncryptionKey.Length;
    //        int j = 0;
    //        byte[] EncryptKey = null;
    //        EncryptKey = new byte[2*i];

    //        for (i = 0; i < EncryptKey.Length; i++)
    //        {
    //            if ((i%2) == 0)
    //            {
    //                EncryptKey[i] = EncryptionKey[j];
    //                j++;
    //            }
    //            else
    //            {
    //                EncryptKey[i] = 0;
    //            }
    //        }

    //        SecretString = Encoding.Default.GetBytes(unencryptedString);

    //        i = SecretString.Length;
    //        j = 0;
    //        byte[] secretStringKorr = new byte[2*i];
    //        for (i = 0; i < secretStringKorr.Length; i++)
    //        {
    //            if ((i%2) == 0)
    //            {
    //                secretStringKorr[i] = SecretString[j];
    //                j = j + 1;
    //            }
    //            else
    //            {
    //                secretStringKorr[i] = 0;
    //            }
    //        }

    //        EncryptedPwd = EncryptData(secretStringKorr, EncryptKey);

    //        return ConvertEncryptedByteDataToEncryptedString(ref EncryptedPwd);
    //    }

    //    public string DecryptString(string encryptedString, string zertifikat)
    //    {
    //        string functionReturnValue = null;


    //        byte[] EncryptedByteData = null;
    //        byte[] AES_PWD = null;

    //        if ((encryptedString.Length == 0))
    //        {
    //            functionReturnValue = "";
    //            return functionReturnValue;
    //        }

    //        if ((encryptedString.Length > 65000))
    //        {
    //            throw new Exception("String to large");
    //        }

    //        AES_PWD = Encoding.Default.GetBytes(zertifikat);
    //        int i = AES_PWD.Length;
    //        int j = 0;
    //        byte[] AES_PWD_Key = null;
    //        AES_PWD_Key = new byte[2*i];

    //        for (i = 0; i < AES_PWD_Key.Length; i++)
    //        {
    //            if ((i%2) == 0)
    //            {
    //                AES_PWD_Key[i] = AES_PWD[j];
    //                j = j + 1;
    //            }
    //            else
    //            {
    //                AES_PWD_Key[i] = 0;
    //            }
    //        }

    //        EncryptedByteData = ConvertEncryptedStringDataToEncryptedByteData(encryptedString);
    //        byte[] decr = DecryptData(EncryptedByteData, AES_PWD_Key);
    //        functionReturnValue = ConvertEncryptedByteDataToEncryptedString(ref decr);
    //        return functionReturnValue;
    //    }
    //}

    public class AESCrypto
    {

        /// <summary>
        /// Encrypts a string
        /// </summary>
        /// <param name="plainText">Text to be encrypted</param>
        /// <param name="password">Password to encrypt with</param>
        /// <param name="salt">Salt to encrypt with</param>
        /// <param name="hashAlgorithm">Can be either SHA1 or MD5</param>
        /// <param name="passwordIterations">Number of iterations to do</param>
        /// <param name="initialVector">Needs to be 16 ASCII characters long</param>
        /// <param name="keySize">Can be 128,192 or 256</param>
        /// <returns>An encrypted string</returns>
        public string Encrypt(string plainText, string password, 
                string salt = "3St0ck!", string hashAlgorithm = "SHA1", int passwordIterations = 2,
                string initialVector = "Q324*ng6r66ulct0", int keySize = 256)
        {
            if (string.IsNullOrEmpty(plainText))
                return string.Empty;
            byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            PasswordDeriveBytes derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
            byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);

            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
         
            byte[] cipherTextBytes = null;
            using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initialVectorBytes))
            {
                using(MemoryStream memStream = new MemoryStream())
                {
                    using(CryptoStream cryptoStream = new CryptoStream(memStream,encryptor,CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainTextBytes,0,plainTextBytes.Length);
                        cryptoStream.FlushFinalBlock();
                        cipherTextBytes = memStream.ToArray();
                        memStream.Close();
                        cryptoStream.Close();
                    }
                }
            }
            symmetricKey.Clear();
            return Convert.ToBase64String(cipherTextBytes);
        }

        public string Decrypt(string cipherText, string password, string salt = "3St0ck!",
                                string hashAlgorithm = "SHA1", int passwordIterations = 2,
                                string initialVector = "Q324*ng6r66ulct0", int keySize = 256)
        {
            if (string.IsNullOrEmpty(cipherText))
                return string.Empty;

            byte[] initialVectorBytes = Encoding.ASCII.GetBytes(initialVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(salt);
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
            PasswordDeriveBytes derivedPassword = new PasswordDeriveBytes(password, saltValueBytes, hashAlgorithm, passwordIterations);
            byte[] keyBytes = derivedPassword.GetBytes(keySize / 8);

            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;

            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
            int byteCount = 0;
            using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initialVectorBytes))
            {
                try
                {
                    using(MemoryStream memStream = new MemoryStream(cipherTextBytes))
                    {
                        using(CryptoStream cryptoStream = new CryptoStream(memStream,decryptor,CryptoStreamMode.Read))
                        {
                                byteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                                memStream.Close();
                                cryptoStream.Close();   
                        }
                    }
                }
                catch (Exception)
                {
                    symmetricKey.Clear();
                    return string.Empty;
                }
            }
            symmetricKey.Clear();
            return Encoding.UTF8.GetString(plainTextBytes, 0, byteCount);
        }
    }


    public static class Crypto
    {
        private readonly static AESCrypto Crypt;
        private static readonly SecureString Cert;

        static Crypto()
        {
            Cert = new SecureString();
            foreach (char c in "NmY0ODZjMzM2MjNiNGUyODVmMmYyMTdhNDIzYTZmNTg2YzUzMjZkNmU0NDUyNDI1NWQyZTM1NDMyNjNlNWYyODQ5YzQ0MjYzNDc3ZDU0MzQ=")
             {
                Cert.AppendChar(c);
             }
            Crypt = new AESCrypto();
        }

        public static string CryptString(string input)
        {
            return Crypt.Encrypt(input, GetKey(Cert));
        }

        public static string DecryptString(string cryptedInput)
        {
            return Crypt.Decrypt(cryptedInput, GetKey(Cert));
        }

        private static string GetKey(SecureString hash)
        {
            try
            {
                string s = hash.ConvertToUnsecureString().Base64Decode();
                return s.Hex2String();
            }
            catch (Exception e)
            {
                throw new Exception("Error in GetKey: " + e.Message);
            }
        }
    }
}